home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / docs / howto / doAPort.me < prev    next >
Encoding:
Text File  |  1992-12-14  |  30.6 KB  |  600 lines

  1. .th
  2. .sp 2
  3. .(l C
  4. \fBPorting Sprite to a New Machine\fR
  5. .sp
  6. Mary Gray Baker
  7. October 1989
  8. .)l
  9. .sp
  10. .sh 1 "The Purpose of this Document"
  11. .pp
  12. Most of the sprite kernel is machine-independent C code that should not
  13. provide too many problems in a port.  The major part of the work in a sprite
  14. port is writing the machine-dependent code, and a large part of this work is
  15. in understanding the detailed behavior of the new machine.  This document
  16. cannot help with the last problem except to mention some of the machine
  17. peculiarities you may need to find out about.  What I hope to do
  18. is help identify and
  19. explain the sections of code you will need to write and suggest a possible order
  20. in which to put together the kernel.  Some of my comments may seem
  21. absurdly obvious to those who already know what they're doing.  I hope mostly
  22. to help those who are in the position I was in, knowing nothing about the task
  23. they've started.
  24. .sp
  25. .sh 1 "What To Know About"
  26. .pp
  27. Before starting the port, there are aspects of the machine and the
  28. environment and the software tools that you must know
  29. about.  I list some of them here in an approximate order as to which you will
  30. need to deal with first in the port.
  31. .sp
  32. \(bu \fBRegister architecture\fR: What is the register architecture of the
  33. machine?  For instance, does it use a set of general purpose registers, or does
  34. it have register windows?  Does it have special-purpose frame pointer or
  35. argument pointer registers?  The first code you write for dealing with
  36. trap handling will need to take the register architecture into account.
  37. .sp
  38. \(bu \fBState registers\fR: What are the special-purpose registers for
  39. representing the state of the machine?  The first trap handlers will need
  40. to be able to save and restore, if not understand, this state.
  41. .sp
  42. \(bu \fBProm print routine\fR: Is there a routine available in the prom
  43. for printing to the display?  If so, this will make life considerably easier
  44. for debugging the first few kernels before your kernel debugger works.
  45. If there is no print routine, are there any diagnostic lights that you can
  46. set and unset to indicate what's going on the in the kernel?  Are there any
  47. debugging facilities from the prom so that you can print out the contents
  48. of areas of memory?  Somehow you will need to be able to get information
  49. about what's gone on inside the kernel.
  50. .sp
  51. \(bu \fBThe downloader\fR: You need to know where your downloader
  52. actually loads the kernel, so that you can give the correct address
  53. to the linker.  If you have the source for the downloader, this is easy to
  54. find out.  If not, you may have to experiment or write your own downloader.
  55. .sp
  56. \(bu \fBThe monitor prom\fR: Does the monitor or boot prom have any
  57. requirements or expectations?
  58. Knowing what the prom can do and what it requires will ease the initial
  59. part of the port considerably.  For instance, if the prom has code for
  60. trap handling, you may be able to let it handle most traps while you test
  61. out your handlers for certain traps.  Also, the prom may use some portion
  62. of the address space that you need to be aware of.  In the sprite sun ports,
  63. we leave the virtual addresses of devices where the prom puts them, since we
  64. haven't had much luck mapping them elsewhere.  This makes a portion of
  65. the virtual address space off limits.  Investigating the files machConst.h
  66. in the mach module and vmXXConst.h (where XX is the machine name) in the
  67. vm module, will show you some of the address considerations on other machines.
  68. .sp
  69. \(bu \fBAlignment rules\fR: Are there alignment issues for memory
  70. accesses?  For instance on the Sparc architecture, you can only access
  71. integers on 4-byte boundaries.  For saving and restoring state in the initial
  72. trap handlers, you need to know about this.
  73. .sp
  74. \(bu \fBHardware trap sequence\fR: What does the hardware do when a trap occurs?
  75. Does it automatically save some state on the stack in a specific form, as on
  76. the sun3's?  Or does it save some state in particular registers of a new
  77. register window, as in the Sparc architecture?  Trap handlers must take this
  78. into account.
  79. .sp
  80. \(bu \fBHardware interrupt sequence\fR: Are interrupts treated differently
  81. than traps?  Is the state saved by the hardware different?  This will most
  82. likely not affect you until you write the first interrupt handlers, but 
  83. you should think about it before writing even the trap handlers, in case there's
  84. a way that you can simplify saving and restoring state for traps and interrupts
  85. by doing it the same way for both.  \fIIf you can make all saving and restoring
  86. of state the same and simple, then you will have your port done much sooner,
  87. since this is the most critical part of the machine-dependent code.\fR
  88. .sp
  89. \(bu \fBRegister conventions\fR: What are the register conventions used in
  90. the compiler?  It is very helpful to use these same conventions in your
  91. assembly code where possible.  It makes it much easier to know which registers
  92. can and cannot be counted on to retain their values after procedure calls or
  93. macros.  If there is some flexibility here, then define your own conventions
  94. that make it possible to call macros and procedures and know which registers
  95. are safe or not.
  96. .sp
  97. \(bu \fBStack conventions\fR: What are the stack conventions used by the
  98. compiler?  It is helpful to use the same conventions where possible so
  99. that it is easy to know what state or registers are saved where on the stack
  100. during any procedure call. 
  101. .sp
  102. \(bu \fBByte order\fR: What is the byte order of the machine?  You'll need
  103. to know this especially when you get to setting up the network headers.
  104. .sp
  105. \(bu \fBInstruction delays\fR: Are there any instruction delays due, say,
  106. to instruction pipelining?  One of the ickiest problems in the sun4 port
  107. was due to a
  108. 3-instruction pipeline delay in updating a state register. 
  109. .sp
  110. \(bu \fBI/O architecture and network interface\fR: How does device DMA work
  111. on the machine?  What are the network interface requirements?  Are there
  112. ranges of addresses that must be reserved?
  113. The network is amongst the first modules
  114. to get working, since you will then be able to run the kernel debugger.
  115. .sp
  116. \(bu \fBMemory architecture\fR: What is the memory architecture of the machine?
  117. Is physical memory contiguous?  Is virtual memory contiguous?  What is the page
  118. size, segment size, etc.?  Is there a cache you will need to handle?
  119. Are there hardware page tables or segment tables?  You may want to be able
  120. to print out portions of their contents for debugging.
  121. How does the hardware inform you of a bus error or segmentation fault?  For
  122. instance, are there bus error registers to read?
  123. You will need to know this
  124. when setting up the virtual memory module.  This is not the first module
  125. to set up, but it is amongst the first.  Amongst previous ports are examples
  126. of how to handle many types of virtual memory problems:  the sun4 port has
  127. non-contiguous virtual memory and a virtually-addressed cache.  To this,
  128. the sparcstation adds non-contiguous physical memory.  Take a look at the
  129. machine-dependent parts of the vm module for different machines for examples.
  130. .sp
  131. \(bu \fBAtomic instructions\fR:  Are there any atomic test-and-set or
  132. similar instructions?  This is not a problem initially, but when you write
  133. the locking code, you will either need the equivalent of an atomic
  134. test-and-set instruction or you will need to enable and disable interrupts
  135. during the locking code.
  136. .sp
  137. .sh 1 "Setting Up"
  138. .sh 2 "Compiler Tools"
  139. .pp
  140. Every port will probably have a different set of problems getting started.
  141. One of the things to consider is where the compiler, assembler, etc., run.
  142. The ideal situation is that you have the source for the compiler and assembler.
  143. If you do, then bring the source code over to sprite, and compile the compiler,
  144. assembler, etc.  so that they can be invoked from different sprite machines
  145. (sun3's sun4's, etc).  Then you will be able to compile code for your new
  146. machine from any sprite machine.  It is important to be able to compile for
  147. your machine within the sprite kernel directory framework, since then you
  148. will be able to make use of automatic Makefiles, include files, etc.  It will
  149. be extremely tedious to set this up differently, and it will be very nasty
  150. to re-integrate your code if you do separate it from the sprite source
  151. directories.  Please see the \fISprite Engineering Manual\fR for the setup of
  152. our source directories.
  153. .pp
  154. A less ideal situation, but still very manageable,
  155. is that you have a compiler, assembler, etc., that
  156. can run on some sprite machine, but not all of them.  In this case, you will
  157. want to do a lot of your work with access to the sprite machine on which you
  158. can compile code for the new machine.
  159. .pp
  160. If the compiler only runs on a non-sprite machine, then one possibility is to
  161. make links via NFS to the sprite kernel source directories from the non-sprite
  162. machine.  If you can do this, then you can still work within and compile into
  163. the sprite directories.  It will be slower work since you will be compiling
  164. across NFS, but it is worth it to do this as opposed to separating your
  165. source management from sprite.  To mount sprite file systems on
  166. another machine running NFS, you need to start up /sprite/daemons/unfsd and
  167. /sprite/daemons/portmap on a sprite machine, and then mount the sprite
  168. file systems with that sprite machine as the source.
  169. .pp
  170. If you can do none of the above, you have an arduous task ahead of you.  There
  171. is probably no good way to imitate the sprite environment on another machine,
  172. so you will probably have to ship a lot of code back and forth.
  173. .sp
  174. .sh 2 "Machine-Dependent Directories and Stub Procedures"
  175. .pp
  176. For some kernel modules, you may want to make a whole separate directory
  177. initially, rather than just a new machine-dependent subdirectory.
  178. This is because
  179. some of the modules, such as the timer module, reference code in practically
  180. all the other modules of the kernel, before you may be willing to deal with
  181. compiling them and getting rid of all the undefined routines.
  182. When possible, it is nice not to create a separate module, since you will avoid
  183. the need to re-integrate your code back into the real module, but it depends
  184. when you feel most confident about your level of patience.
  185. .pp
  186. How you stub out code is a matter of personal preference,
  187. but as you go about the port, you will probably
  188. want at some points to include modules for which you haven't yet written all
  189. the machine-dependent procedures.   You can stub out each procedure in the
  190. module where you find it, or you could do what I found easiest.  In
  191. main/machine.md/stubs.c I put the stub definitions to all routines as yet
  192. undefined.  This makes it easy to see what's left to do.  When there are no more
  193. stubs left in stubs.c, you're just about done.
  194. .sp
  195. .sh 1 "A List of Modules with Machine-Dependent Code"
  196. .pp
  197. Here is a list of the modules in sprite that have machine-dependent code, along
  198. with some description of the purpose of the code.
  199. .sp
  200. \fBmach\fR:  This is the major machine-dependent module.  In fact, it contains
  201. no machine-independent code.  This is where the trap handlers, interrupt
  202. handlers and context-switching code reside.  The definitions of structures
  203. for saving and restoring state are in this module.  The lowest level routines
  204. for setting up the state of new processes are in this module.  It also contains
  205. routines to access values in the monitor prom and various other hardware
  206. registers.
  207. .sp
  208. \fBtimer\fR: The code for the timer and its software call-back queues is in
  209. this module.  The machine-dependent code is for the timer device.
  210. .sp
  211. \fBdbg\fR: This module contains only machine-dependent code implementing
  212. the kernel interface to the kernel debugger.
  213. .sp
  214. \fBnet\fR: This module contains the machine-independent interface to the
  215. network and also the machine-dependent code below that.
  216. .sp
  217. \fBdev\fR: Code for devices goes in this module.  There's a machine-independent
  218. level for block devices, disks, SCSI devices, etc., and there's a
  219. machine-dependent layer below this for the device drivers.
  220. .sp
  221. \fBvm\fR: This module too in separated into a machine-independent software
  222. level and a machine-dependent level below this.  The machine-independent level
  223. is a software representation of contexts, segment tables and page tables and
  224. the operations on them.  This level makes calls into the machine-dependent
  225. level which operates on the hardware's memory management tables.
  226. .sp
  227. \fBproc\fR: The code for setting up, starting, and ending processes, or
  228. otherwise changing their state, is in this module.  There is little
  229. machine-dependent code, but some is necessary for recognizing different object
  230. file formats, and for migration differences between machines.
  231. .sp
  232. \fBmain\fR:  This module consists only of machine-dependent code.  This is
  233. where the main() routine of sprite resides.  This routine is called from
  234. the initial boot code and calls all the initialization routines for the
  235. different modules.  It then starts up a kernel process "Init" which executes
  236. the boot command script that starts up the first user processes.
  237. .sp
  238. \fBprof\fR: This module is used only for kernel profiling.  The
  239. machine-dependent code is used to determine the value of the
  240. PC of the caller of a profiling routine mcount(), the PC of the caller of
  241. the caller, and some stack pointer information.
  242. .sp
  243. \fBmem\fR:  The memory allocation code is in this module.  The
  244. machine-dependent code is used to determine the caller's PC.
  245. .sp
  246. \fBrpc\fR:  This module contains the code for kernel-to-kernel remote
  247. procedure calls.  The only machine-dependent code is a routine to determine
  248. an inter-fragment delay constant appropriate for the machine.
  249. .sp
  250. \fButils\fR: A miscellaneous bunch of useful routines is in this module.
  251. The only machine-dependent code implements a table of special function
  252. keys to do such things as abort to console mode.  Only part of this table
  253. is implemented in this module.  Most of the console commands are implemented
  254. in dev/devConsoleCmd.c.
  255. .sp
  256. \fBlibc\fR: This module contains soft links to those files in the the C
  257. library that the kernel makes use of.  The machine-dependent code consists
  258. of whatever necessary arithmetic functions (such as unsigned multiply) 
  259. aren't defined by the hardware, and perhaps alloca(), varargs, etc.
  260. .sp
  261. \fBlib/c\fR: This is the user C library.  There is some machine-dependent
  262. code necessary for user programs.  This includes the start-up code in crt
  263. and code such as setjmp and perhaps software floating-point routines.
  264. .sp
  265. \fBinitsprite\fR: The main procedure in sprite starts up a kernel process
  266. called Init which exec's a program called initsprite.  You will need an
  267. initsprite for your new machine.  The first initsprite should be very simple
  268. and perhaps only execute one system call.  The real initsprite then executes
  269. the bootcmds script.
  270. .sp
  271. \fBbootcmds\fR: This script is executed by initsprite, the first user process.
  272. It starts up all the daemons.  You may not want your first version of bootcmds
  273. to start up all the daemons until you know that you can exec scripts
  274. successfully and until you have all the daemons compiled for the new machine.
  275. .sp
  276. .sh 1 "Where to Start and What to Do Next"
  277. .pp
  278. Many of the suggestions here are a result of my experience with the sun4 port.
  279. Some of the
  280. suggestions may not apply to different sorts of machines, but perhaps something
  281. similar will work.
  282. Along the way, if you need more details about initial steps in some of the
  283. modules, look at old RCS'd versions for the sun4 port.  The RCS comments
  284. explain the porting steps taken in each subsequent version of the file.
  285. As you add working modules to the system, add the
  286. calls to initialize them in mainInit.c.  You'll know you're close to done when
  287. your mainInit.c looks like that of the other machines!
  288. .sp
  289. .sh 2 "First Kernel - Hello World"
  290. .pp
  291. A good first kernel consists only of simple versions of mainInit.c, machMon.h,
  292. and bootSysAsm.s.  All it should do is turn off interrupts and call main().
  293. All main() should do is print out "Hello World", or the equivalent if you're
  294. using diagnostic lights or such instead of a display.
  295. .pp
  296. The difficult part of the first kernel will just be getting things set up,
  297. and figuring out where the downloader puts your kernel, if you don't have
  298. source to the downloader.
  299. .pp
  300. As an example of the sort of thing that can go wrong already, on the sun4 the
  301. prom print routine called deeply enough to cause an overflow trap when I'd
  302. turned off traps.  This caused a watchdog reset of the machine.  So I stopped
  303. turning off traps, and used the prom's trap handlers initially by not resetting
  304. the trap base register.  I also left the stack pointer alone, leaving it as
  305. the the prom's stack pointer.
  306. .sp
  307. .sh 2 "Adding Trap Table Location"
  308. .pp
  309. A good next step is to try using your own trap table by having each entry
  310. in your trap table just indirect off to the prom's trap table.  This is just
  311. a good way of making sure you're setting up the trap base register correctly
  312. and that you understand the layout and alignment of the trap table.  If there
  313. is no prom trap table on your machine, then this obviously isn't a good next
  314. step.  This kernel will involve machTrap.s and perhaps some of the header
  315. files in the mach module.
  316. .sp
  317. .sh 2 "Copying Kernel to its Real Location"
  318. .pp
  319. Make a first pass at deciding on the virtual memory layout of the kernel and
  320. then try getting the kernel to copy itself to that location.  (See the sun4.md
  321. bootSysAsm.s file in the mach module as an example of how to do this.)  Try
  322. using your own kernel stack.  This kernel will involve some of the mach
  323. header files, and the machine-dependent header file vmXXConst.h (where XX is
  324. the name of the machine) in the vm module.
  325. .pp
  326. Generally in sprite, the kernel resides in high memory, in all contexts,
  327. and user processes reside
  328. in low memory.  On the sun4, I also had to take into account a hole in the
  329. virtual address space and found it convenient to put the kernel on the high
  330. side of that hole.  The kernel also keeps one context to itself.  This means
  331. it can make use of low memory in that context (the sun4 uses it for 32-bit
  332. dvma), but there's no standard use for this.
  333. .pp
  334. You may want to wait until later to try copying the kernel, but I found it
  335. convenient to do it at this point, since it meant that bootSysAsm.s became
  336. just about complete, it can be done without any of the trap or interrupt
  337. code, and it was nice to know it all worked.
  338. .sp
  339. .sh 2 "First Traps"
  340. .pp
  341. If there are common traps such as register window overflow and underflow
  342. traps, now is a good time to make the trap table point to your
  343. versions of these traps to test them out.  These first traps can be coded
  344. just for the kernel cases, ignoring user processes for a while.  This will test
  345. your code for saving and restoring kernel state.  This kernel will involve
  346. changes to machTrap.s.
  347. .sp
  348. .sh 2 "Timer Interrupts"
  349. .pp
  350. A good next step is to get interrupts working.
  351. As mentioned before, your life will be easier if saving and restoring state
  352. for interrupts or entering the debugger works the same way as saving and
  353. restoring state for traps.
  354. .pp
  355. On most machines,
  356. the first interrupt to try handling is the timer interrupt, since the timer
  357. is required for many operations.  For the timer
  358. module, you may want to create a separate module, stripping out the
  359. machine-independent code since you may not yet want to compile all the other
  360. modules referenced by the timer module.  Besides the timer module, this kernel
  361. will involve machIntr.s and perhaps other files in the mach module.  You will
  362. need to add a call in mainInit.c to initialize the timer code, perhaps
  363. by calling Timer_TimerInit() and Timer_TimerStart() both.
  364. .sp
  365. .sh 2 "Network Interrupts and Debugger"
  366. .pp
  367. Depending on how much you know about the network interface, you may be able
  368. to skip putting together a serial line debugger.  In this case, the next
  369. modules to try are the network module and the dbg module.  If you can get
  370. these to work, you will have a kernel debugger!
  371. .pp
  372. You will need to add the support for
  373. network interrupts in the mach module and calls in mainInit.c to initialize
  374. the net and dbg modules (Dbg_Init() and something like NetIEInit() to do
  375. the lower level network initialization).  You will also need to call
  376. Vm_BootInit().  This does not mean that you need to get the whole virtual
  377. memory module working.  It just means that some variables need to be initialized
  378. for the sake of the debugger and network modules.  After Vm_BootInit, memory
  379. can be allocated by calling Vm_BootAlloc() or Vm_RawAlloc().  You should also
  380. be able to call
  381. Sync_Init() in its place in the boot sequence.  A couple places in the
  382. net module may need to be changed temporarily to call Vm_BootAlloc() instead
  383. of malloc() until the rest of virtual memory is working.
  384. .pp
  385. It is probably easiest to take the code from another machine's dbg module and
  386. modify it for the new machine.
  387. Some of the code, for instance to switch contexts, can only be called
  388. after more of
  389. the virtual memory system has been implemented.  As an example, the code
  390. surrounded by #ifndef FIRST_RUN in the sun4 dgb module is code that should not
  391. be executed until the vm module is fully functional.  There are also
  392. virtual address ranges checked in the dbg module that will need to be modified
  393. for your machine.
  394. .pp
  395. It's also time to figure out
  396. where you want to put the debugger stack, since it uses its own stack.  This
  397. can be statically allocated.  8K bytes is enough.
  398. One thing to note is that saving state, switching stacks and entering the
  399. debugger is a lot like context switching, and you may be able to use and test
  400. some of your context switching code here.  The dbg and network modules
  401. are particularly sensitive to alignment problems.  If things aren't working,
  402. make sure that structures are aligned as they should be.  For instance, on the
  403. sun4 and machines with similar alignment problems, network structures must be
  404. word-aligned.  This
  405. means that the 14-byte ethernet header that precedes the structure must be
  406. aligned on an odd short-word boundary.
  407. .pp
  408. If your machine has register windows, make sure to flush all the windows
  409. before entering the debugger (and before switching to the debugger stack)
  410. so that all the state really is on the kernel stack.
  411. You will need to pass the trap state to the debugger, and you
  412. will need to restore state from the same place afterwards, since the debugger
  413. must be able to modify the register state of the trap.  To simplify this on
  414. the sun4, I pass the debugger a pointer to the actual trap state that was saved
  415. on the stack.  This means that restoring state is done just by returning
  416. from the trap as usual and saving state for the debugger is not a special case.
  417. .pp
  418. A final point about the network module, is that timing problems may come into
  419. play here.  There is a macro to handle delays: MACH_DELAY, defined in
  420. the mach module.
  421. You will want to adjust the number of loops these delay
  422. macros go through to something appropriate to the MIPS rating of your machine,
  423. or else you may not delay long enough or you may delay for too long when
  424. dealing with devices.  (There is also a wart in the Intel driver,
  425. NET_IE_DELAY(), that you need to set if you are using this driver.  This should
  426. be changed to use MACH_DELAY.)  There is a machine-dependent file in the rpc
  427. module, rpcDelays.c, to set an inter-fragment delay for input and output
  428. packets.  You may need to adjust this constant as well.
  429. .sp
  430. .sh 2 "Other Traps and Interrupts"
  431. .pp
  432. Once the debugger is working, you may want to add the code to handle other types
  433. of interrupts and traps.  If you've been indirecting to a prom trap
  434. table for some traps, you can now switch to handling all the traps directly in
  435. your own trap table.
  436. .pp
  437. One issue is whether you'd like to make an attempt at binary compatibility
  438. with the user software already running on your machine under its old operating
  439. system.
  440. If there's a possibility of doing this, then one way to make it easier is to
  441. take some care in picking your trap numbers.  Pick a different system call
  442. trap number for sprite system calls than was used for the old system calls.
  443. This way,
  444. if sprite recognizes both trap numbers, it will know whether it has a real
  445. system call, or a foreign system call to emulate if it can.
  446. .sp
  447. .sh 2 "Virtual Memory"
  448. .pp
  449. Virtual memory is the next module to get working.  This may be a slow one, since
  450. it's large and there may be a lot of debugging to do.  This is why it is
  451. good to have the debugger working first!
  452. .pp
  453. Virtual memory is initialized in two parts.  Vm_BootInit() is called early
  454. on in the boot sequence.  After it is called, memory can be allocated using
  455. Vm_BootAlloc().  Later in the boot sequence, Vm_Init() is called.  Malloc()
  456. can be used from that point on.  Try adding in calls to some of the modules
  457. initialized between Vm_BootInit() and Vm_Init(), since most of this should work.
  458. Dependencies between some of these modules change from time to time, so you may
  459. need to shuffle the order of some calls temporarily while porting.
  460. .pp
  461. Virtual memory was the hardest part of the sun4 port, mostly due to problems
  462. with signed arithmetic showing up, since the sun4 port was the first to have
  463. kernel addresses high enough to be negative.  If this could be true for your
  464. machine, you will want to be particularly careful with the machine-dependent
  465. code.  It could even be easier to write it from scratch than to try to fix an
  466. existing file to suit your needs.
  467. .pp
  468. Adding virtual memory at this point won't test out your page fault handling
  469. code.  For this you must wait until you have user processes.
  470. .sp
  471. .sh 2 "Context Switching and Synchronization"
  472. .pp
  473. The mem module and stdlib should be included now.  Real malloc()'s can be
  474. called, so the hacks in the net module to call Vm_BootAlloc() or Vm_RawAlloc()
  475. can be changed to calls to malloc().
  476. .pp
  477. Now it's time to get process initialization and context switching working.
  478. A nice test of this is to have Init() (called by main()) fork a process
  479. and have the 2 processes
  480. play tag over a monitor lock by having each signal the other over their
  481. separate conditions.  This will test your synchronization and locking
  482. and context switching code to some extent.  For debugging purposes, it may
  483. help you to know that in sprite, the forked child runs before the parent
  484. runs again.  The code to set up the state and run a new process is in
  485. the mach module.  Mach_SetupNewState() sets up the initial state for
  486. a process that is forked.  The state of a new process is set up to look as
  487. if it was just in the middle of a context switch, and when it is first run,
  488. it is context-switched in with the initial PC set to Sched_StartKernProc(),
  489. which is in turn passed a PC at which to start executing. 
  490. .sp
  491. .sh 2 "User Processes and System Calls"
  492. .pp
  493. This next kernel can try running the first user processes.
  494. For this you will need
  495. to write the code for start() in crt/machine.md/start.s in the user C library.
  496. To understand what to put in the startup code, you should look at
  497. DoExec() in procExec.c.  This sets up the argument array and environment
  498. array for the new process, and the startup code must know how to access these
  499. arrays.
  500. In main(), the kernel forks a kernel
  501. process, Init, which exec's a user process called initsprite.  You will be
  502. testing the
  503. first exec of a user process here.  Although the real initsprite execs a shell
  504. script called bootcmds (which will test the forking and exec'ing of processes
  505. from user processes),
  506. your first initsprite should probably be much simpler since you need to test
  507. signal handling, csh, and other capabilities first.
  508. You will also be testing out your
  509. page fault code for the first time.
  510. .pp
  511. To see if anything is working, the first user process, initsprite, should try
  512. to execute a
  513. simple system call that doesn't require copying data in or out of the
  514. kernel and it should be a system call where it's possible to see if it worked
  515. or not.  A good system call is "Sys_Shutdown()" since the kernel will print out
  516. "syncing disks" if it worked.
  517. .sp
  518. .sh 2 "Signal Handling"
  519. .pp
  520. Signal handling is the next thing user processes must be able to do.  A good
  521. first test is to have initsprite signal itself with an interrupt.  The signal
  522. handler should print something out so that you know it worked.  Initsprite
  523. will also have to open the console so that it can write this message to it.
  524. A next test is to have initsprite fork many processes and signal them.
  525. This might be your first test of a user process forking a process.
  526. ." XXX Explain how signal handling works in sprite? XXX
  527. .pp
  528. By now you should have all the sprite modules compiled for your machine, with
  529. whatever modules you made separate copies of (the timer module, for instance)
  530. integrated back into the real modules.  Some modules, such as prof,
  531. you may not use for a while, but it's easier to have them all compiled and
  532. linked in, even if some of the machine-dependent calls are still stubs.
  533. .sp
  534. .sh 2 "Getting Csh Working"
  535. .pp
  536. The next things that a user process must be able to do are all required for
  537. getting csh working.  This makes csh a good next test.  Alloca() and setjmp()
  538. are both required.  Depending on your new machine, these may or may not
  539. be trivial to add.  They reside in the kernel C library module.  The other
  540. requirement is that user processes must be
  541. able to fork other processes.  This is also a stronger test
  542. or your virtual memory system.
  543. .sp
  544. .sh 2 "Debugging User Processes"
  545. .pp
  546. It's a good idea now to make sure you can run a user process debugger, since
  547. this will help for uncovering kernel bugs affecting user processes.  Also,
  548. process initialization for a process started in the debugger is somewhat
  549. different than that of a regular process, so this may uncover other bugs.
  550. .sp
  551. .sh 2 "Finishing Off Bootcmds"
  552. .pp
  553. Try executing a real bootcmds script that starts up various daemons.  Problems
  554. encountered here are likely to be in the virtual memory system and the following
  555. stress test may help you isolate them.
  556. .sp
  557. .sh 2 "Stressing Virtual Memory"
  558. .pp
  559. After csh seems to run, a good test to stress virtual memory is the pager
  560. program.  Try it out with a variety of arguments, including dirtying pages.
  561. .sp
  562. .sh 2 "Caching, COW, etc"
  563. .pp
  564. If there are other features of your machine, such as a virtually-addressed
  565. cache, that you haven't tried out yet, now is a good time, since all the
  566. basics in the system are working.  If you haven't tried out Copy-On-Write,
  567. you should do so now.  If you have a virtually-addressed cache, you may find
  568. that COW is hard to get working and isn't too helpful an optimization.
  569. .sp
  570. .sh 2 "Other Devices"
  571. .pp
  572. If you have disks or tape drives or anything, try them out.
  573. .sp
  574. .sh 2 "Process Migration"
  575. .pp
  576. If you've got more than one or two of the new machine, then try out process
  577. migration.  This will involve writing a few more pieces of kernel code that
  578. were stubbed out - the encapsulate and unencapsulate routines for migration
  579. state in the various modules.
  580. .sp
  581. .sh 2 "Profiling the Kernel"
  582. .pp
  583. To be able to profile the kernel (by calling the kprof command) you will need
  584. to write the final pieces of kernel code that were stubbed out of the prof
  585. module.
  586. .sp
  587. .sh 2 "Done"
  588. .pp
  589. If there are no more stubs in main/machine.md/stubs.c or wherever you've been
  590. stubbing out undefined routines, then you're done!
  591. ." .sp
  592. ." .sh 1 "A List of Test Programs"
  593. ." .pp
  594.  
  595.  
  596.  
  597.  
  598.  
  599.  
  600.